// 版权所有2011 Go作者。版权所有。
// 此源代码的使用受BSD样式的约束
// 可以在许可证文件中找到的许可证。

// 包驱动程序定义要由数据库实现的接口
// 由包sql使用的驱动程序。
// None
// 大多数代码应该使用包sql。
// None
// 驱动程序接口随着时间的推移而发展。司机应实施
// 连接器和驱动器上下文接口。
// Connector.Connect和Driver.Open方法不应返回ErrBadConn。
// ErrBadConn只能从验证器、会话重置器或
// 如果连接已处于无效（如关闭）状态，则为查询方法。
// None
// 所有Conn实施应实现以下接口：
// Pinger、sessionreset和验证器。
// None
// 如果支持命名参数或上下文，则驱动程序的Conn应实现：
// ExecContext、QueryContext、ConnPareContext和ConnBeginTx。
// None
// 要支持自定义数据类型，请实现NamedValueChecker。名称值检查器
// 还允许查询通过返回
// ErrRemoveArgument来自CheckNamedValue。
// None
// 如果支持多个结果集，则行应实现RowsNextResultSet。
// 如果驱动程序知道如何描述返回结果中存在的类型
// 它应该实现以下接口：RowsColumnTypeScanType，
// RowsColumnTypeDatabaseTypeName、RowsColumnTypeLength、RowsColumnTypeNullable、，
// 和RowsColumnTypePrecisionScale。给定的行值也可以返回一个行
// 类型，它可以表示数据库游标值。
// None
// 在使用后将连接返回到连接池之前，IsValid是
// 如果实现，则调用。在将连接重新用于另一个查询之前，
// 如果实现，则调用ResetSession。如果连接从未返回到
// 连接池，但立即重用，然后在调用之前调用ResetSession
// 重用，但不调用IsValid。
package driver

import (
	"context"
	"errors"
	"reflect"
)

// 值是驱动程序必须能够处理的值。
// 它可以是nil，一种由数据库驱动程序的NamedValueChecker处理的类型
// 接口或以下类型之一的实例：
// None
// int64
// 浮动64
// 布尔
// []字节
// 一串
// 时间，时间
// None
// 如果驱动程序支持游标，则返回值也可以实现Rows接口
// 在这个包裹里。例如，当用户选择光标时，使用此选项
// 例如“从dual中选择光标（从my_表中选择*）”。如果行
// 在“选择关闭”对话框中，光标行也将关闭。
type Value interface{}

// NamedValue同时保存值名称和值。
type NamedValue struct {
	// 如果名称不为空，则应将其用于参数标识符和
	// 不是顺序位置。
	// None
	// 名称将没有符号前缀。
	Name string

	// 参数的顺序位置从一开始，并始终设置。
	Ordinal int

	// 值是参数值。
	Value Value
}

// 驱动程序是必须由数据库实现的接口
// 驾驶员
// None
// 数据库驱动程序可以实现DriverContext以进行访问
// 对于上下文，并且对于连接池只解析一次名称，
// 而不是每次连接一次。
type Driver interface {
	// Open返回到数据库的新连接。
	// 名称是驱动程序特定格式的字符串。
	// None
	// Open可能会返回缓存连接（以前的一个）
	// 关闭），但这样做是不必要的；sql包
	// 维护空闲连接池以实现高效的重用。
	// None
	// 返回的连接一次仅由一个goroutine使用
	// 时间
	Open(name string) (Conn, error)
}

// 如果驱动程序实现DriverContext，则sql.DB将调用
// 打开连接器以获取连接器，然后调用
// 该连接器的连接方法，以获得每个所需的连接，
// 而不是为每个连接调用驱动程序的Open方法。
// 两步序列允许驱动程序只解析一次名称
// 并且还提供对每个连接上下文的访问。
type DriverContext interface {
	// OpenConnector必须以与Driver.Open相同的格式解析名称
	// 解析name参数。
	OpenConnector(name string) (Connector, error)
}

// 连接器代表固定配置中的驱动程序
// 并且可以创建任意数量的等效接头以供使用
// 通过多次出游。
// None
// 可以将连接器传递到sql.OpenDB，以允许驱动程序
// 实现自己的sql.DB构造函数，或由
// DriverContext的OpenConnector方法，以允许驱动程序
// 访问上下文并避免重复解析驱动程序
// 配置
// None
// 如果连接器实现io.Closer，则sql包的DB.Close
// 方法将调用Close并返回错误（如果有）。
type Connector interface {
	// Connect返回到数据库的连接。
	// Connect可能会返回缓存连接（以前的一个）
	// 关闭），但这样做是不必要的；sql包
	// 维护空闲连接池以实现高效的重用。
	// None
	// 提供的上下文。上下文仅用于拨号目的
	// （请参阅net.DialContext）并且不应存储或用于
	// 其他目的。仍应使用默认超时
	// 当作为连接池拨号时，可以调用Connect
	// 异步到任何查询。
	// None
	// 返回的连接一次仅由一个goroutine使用
	// 时间
	Connect(context.Context) (Conn, error)

	// 驱动程序返回连接器的底层驱动程序，
	// 主要是为了保持与驱动程序方法的兼容性
	// 在sql.DB上。
	Driver() Driver
}

// 一些可选接口的方法可能会将ErrSkip返回给
// 在运行时指示快速路径不可用，并且sql
// 包应继续运行，就好像可选接口不可用一样
// 执行。ErrSkip仅在显式
// 记录在案。
var ErrSkip = errors.New("driver: skip fast-path; continue as if unimplemented")

// 驱动程序应返回ErrBadConn以向sql发出信号
// 程序包，以确保驱动程序.Conn处于错误状态（例如服务器
// 之前已关闭连接）和sql包
// 在新连接上重试。
// None
// 为防止重复操作，不应返回ErrBadConn
// 如果数据库服务器有可能
// 进行了手术。即使服务器发回错误，
// 你不应该返回ErrBadConn。
var ErrBadConn = errors.New("driver: bad connection")

// Pinger是一个可选接口，可由Conn实现。
// None
// 如果Conn未实现Pinger，则sql包的DB.Ping和
// DB.PingContext将检查是否至少有一个Conn可用。
// None
// 如果Conn.Ping返回ErrBadConn，则DB.Ping和DB.PingContext将被删除
// 游泳池里的康涅狄格。
type Pinger interface {
	Ping(ctx context.Context) error
}

// Execer是一个可选接口，可由Conn实现。
// None
// 如果Conn既不实现ExecContext也不实现Execer，
// sql包的DB.Exec将首先准备一个查询，执行语句，
// 然后关闭该语句。
// None
// Exec可能返回ErrSkip。
// None
// 不推荐使用：驱动程序应改为实现ExecContext。
type Execer interface {
	Exec(query string, args []Value) (Result, error)
}

// ExecContext是一个可选接口，可由Conn实现。
// None
// 如果Conn未实现ExecContext，则sql包的DB.Exec
// 将退回到执行者手中；如果Conn也没有实现Execer，
// Exec将首先准备一个查询，执行语句，然后
// 结束声明。
// None
// ExecerContext可能返回ErrSkip。
// None
// ExecContext必须遵守上下文超时，并在取消上下文时返回。
type ExecerContext interface {
	ExecContext(ctx context.Context, query string, args []NamedValue) (Result, error)
}

// Queryer是可由Conn实现的可选接口。
// None
// 如果Conn既不实现QueryerContext也不实现Queryer，
// sql包的DB.Query将首先准备一个查询，执行语句，
// 然后关闭该语句。
// None
// 查询可能返回ErrSkip。
// None
// 不推荐使用：驱动程序应改为实现QueryerContext。
type Queryer interface {
	Query(query string, args []Value) (Rows, error)
}

// QueryerContext是可由Conn实现的可选接口。
// None
// 如果Conn未实现QueryerContext，则sql包的DB.Query
// 将退回到Queryer；如果Conn也没有实现Queryer，
// Query将首先准备一个查询，执行语句，然后
// 结束声明。
// None
// QueryerContext可能返回ErrSkip。
// None
// QueryerContext必须遵守上下文超时，并在取消上下文时返回。
type QueryerContext interface {
	QueryContext(ctx context.Context, query string, args []NamedValue) (Rows, error)
}

// Conn是与数据库的连接。它不是同时使用的
// 通过多次出游。
// None
// Conn被认为是有状态的。
type Conn interface {
	// Prepare返回绑定到此连接的已准备语句。
	Prepare(query string) (Stmt, error)

	// 关闭会使任何电流失效并可能停止
	// 准备报表和交易，标记此
	// 连接不再使用。
	// None
	// 因为sql包维护一个可用的
	// 连接和呼叫仅在剩余的
	// 空闲连接时，驾驶员不必
	// 自己做连接缓存。
	// None
	// 驱动程序必须确保所有网络呼叫由Close完成
	// 不要无限期地阻塞（例如，应用超时）。
	Close() error

	// 开始启动并返回一个新事务。
	// None
	// 不推荐使用：驱动程序应改为（或另外）实现ConnBeginTx。
	Begin() (Tx, error)
}

// ConnPareContext通过上下文增强了Conn接口。
type ConnPrepareContext interface {
	// PrepareContext返回绑定到此连接的已准备语句。
	// 背景是为了准备声明，
	// 它不能将上下文存储在语句本身中。
	PrepareContext(ctx context.Context, query string) (Stmt, error)
}

// IsolationLevel是存储在TxOptions中的事务隔离级别。
// None
// 应将此类型视为与sql.IsolationLevel相同
// 在上面定义了任何值。
type IsolationLevel int

// TxOptions保存事务选项。
// None
// 应将此类型视为与sql.TxOptions相同。
type TxOptions struct {
	Isolation IsolationLevel
	ReadOnly  bool
}

// ConnBeginTx使用上下文和TxOptions增强了Conn接口。
type ConnBeginTx interface {
	// BeginTx启动并返回一个新事务。
	// 如果用户取消了上下文，则sql包将
	// 在放弃和关闭连接之前调用Tx.回滚。
	// None
	// 这必须检查opts.Isolation以确定是否存在一个集合
	// 隔离级别。如果驱动程序不支持非默认
	// 级别，如果存在非默认隔离级别，则设置一个
	// 如果不支持，则必须返回错误。
	// None
	// 还必须检查opts.ReadOnly以确定
	// 值为true，以设置只读事务属性（如果支持）
	// 如果不支持，则返回错误。
	BeginTx(ctx context.Context, opts TxOptions) (Tx, error)
}

// 会话重置器可由Conn实现，以允许驱动程序重置会话
// 与连接关联的会话状态，并发出连接错误的信号。
type SessionResetter interface {
	// 在对连接执行查询之前调用ResetSession
	// 如果以前使用过该连接。如果驱动程序返回ErrBadConn
	// 连接被丢弃。
	ResetSession(ctx context.Context) error
}

// 验证器可以由Conn实现，以允许驱动程序
// 指示连接是否有效或是否应放弃连接。
// None
// 如果实现，驱动程序可能会从查询中返回基本错误，
// 即使连接池应该丢弃该连接。
type Validator interface {
	// 在将连接放置到中之前调用IsValid
	// 连接池。如果返回false，则将放弃连接。
	IsValid() bool
}

// 结果是查询执行的结果。
type Result interface {
	// LastInsertId返回数据库自动生成的ID
	// 例如，在插入到具有主属性的表之后
	// 钥匙
	LastInsertId() (int64, error)

	// RowsAffected返回受影响的行数
	// 查询
	RowsAffected() (int64, error)
}

// Stmt是一个预先准备好的语句。它绑定到一个Conn，而不是
// 由多个goroutine同时使用。
type Stmt interface {
	// 关闭语句。
	// None
	// 从Go 1.1开始，如果Stmt正在使用，则不会关闭
	// 任何疑问。
	// None
	// 驱动程序必须确保所有网络呼叫由Close完成
	// 不要无限期地阻塞（例如，应用超时）。
	Close() error

	// NumInput返回占位符参数的数量。
	// None
	// 如果NumInput返回>=0，则sql包将进行健全性检查
	// 调用方的参数计数并将错误返回给调用方
	// 在调用语句的Exec或Query方法之前。
	// None
	// 如果驱动程序不知道，NumInput也可能返回-1
	// 它的占位符数。在这种情况下，sql包
	// 不会对Exec或查询参数计数进行健全性检查。
	NumInput() int

	// Exec执行不返回行的查询，例如
	// 作为插入或更新。
	// None
	// 不推荐：驱动程序应改为（或另外）实现StmtExecContext。
	Exec(args []Value) (Result, error)

	// 查询执行可能返回行的查询，例如
	// 选择
	// None
	// 不推荐：驱动程序应改为（或另外）实现StmtQueryContext。
	Query(args []Value) (Rows, error)
}

// STMTEXCECONTEXT通过为Exec提供上下文来增强Stmt接口。
type StmtExecContext interface {
	// ExecContext执行不返回行的查询，例如
	// 作为插入或更新。
	// None
	// ExecContext必须遵守上下文超时并在取消时返回。
	ExecContext(ctx context.Context, args []NamedValue) (Result, error)
}

// StmtQueryContext通过提供带有上下文的查询来增强Stmt接口。
type StmtQueryContext interface {
	// QueryContext执行可能返回行的查询，例如
	// 选择
	// None
	// QueryContext必须遵守上下文超时并在取消时返回。
	QueryContext(ctx context.Context, args []NamedValue) (Rows, error)
}

// 可以从NamedValueChecker返回ErrRemoveArgument以指示
// sql包不将参数传递给驱动程序查询接口。
// 接受查询特定的选项或结构时返回，这些选项或结构不是
// SQL查询参数。
var ErrRemoveArgument = errors.New("driver: remove argument from query")

// NamedValueChecker可以选择由Conn或Stmt实现。它提供
// 驱动程序可以控制更多的Go和数据库类型，超出默认值
// 允许的值类型。
// None
// sql包按以下顺序检查值检查器：，
// 在找到的第一个匹配项处停止：Stmt.NamedValueChecker，Conn.NamedValueChecker，
// Stmt.ColumnConverter，DefaultParameterConverter。
// None
// 如果CheckNamedValue返回ErrRemoveArgument，则NamedValue将不包括在
// 最后的查询参数。这可用于将特殊选项传递给
// 查询本身。
// None
// 如果返回ErrSkip，则检查列转换器错误
// 路径用于参数。驾驶员可能希望在之后返回
// 他们已经用尽了自己的特例。
type NamedValueChecker interface {
	// 在将参数传递给驱动程序之前调用CheckNamedValue
	// 并被称为以代替任何列转换器。CheckNamedValue必须执行类型
	// 对驱动程序进行适当的验证和转换。
	CheckNamedValue(*NamedValue) error
}

// 如果
// 语句知道自己列的类型，可以从
// 将任何类型转换为驱动程序值。
// None
// 不推荐使用：驱动程序应实现NamedValueChecker。
type ColumnConverter interface {
	// ColumnConverter返回所提供数据的ValueConverter
	// 列索引。如果特定列的类型未知
	// 或者不应该特别处理，DefaultValueConverter
	// 可以退货。
	ColumnConverter(idx int) ValueConverter
}

// 行是对已执行查询结果的迭代器。
type Rows interface {
	// Columns返回列的名称。人数
	// 结果的列是根据
	// 片如果特定列名未知，则为空
	// 应该为该条目返回字符串。
	Columns() []string

	// Close关闭行迭代器。
	Close() error

	// 调用Next将下一行数据填充到
	// 提供的切片。提供的切片将是相同的
	// 列（）宽时的大小。
	// None
	// 当没有更多行时，Next应该返回io.EOF。
	// None
	// dest不应写入Next外部。照顾
	// 在关闭不修改的行时应采取
	// 存放在dest中的缓冲区。
	Next(dest []Value) error
}

// RowsNextResultSet通过提供一种发送信号的方式来扩展Rows接口
// 驱动程序将前进到下一个结果集。
type RowsNextResultSet interface {
	Rows

	// 在当前结果集的末尾调用HasNextResultSet，然后
	// 报告当前结果集之后是否有其他结果集。
	HasNextResultSet() bool

	// NextResultSet使驱动程序前进到下一个结果集
	// 如果当前结果集中还有剩余的行。
	// None
	// 当没有更多结果集时，NextResultSet应返回io.EOF。
	NextResultSet() error
}

// RowsColumnTypeScanType可以通过行实现。它应该会回来
// 可用于将类型扫描到的值类型。例如，数据库
// 列类型“bigint”应返回“reflect.TypeOf（int64（0））”。
type RowsColumnTypeScanType interface {
	Rows
	ColumnTypeScanType(index int) reflect.Type
}

// RowsColumnTypeDatabaseTypeName可以通过行实现。它应该返回
// 不带长度的数据库系统类型名称。类型名称应为大写。
// 返回类型的示例：“VARCHAR”、“NVARCHAR”、“VARCHAR2”、“CHAR”、“TEXT”，
// “DECIMAL”、“SMALLINT”、“INT”、“BIGINT”、“BOOL”、“[]BIGINT”、“JSONB”、“XML”，
// “时间戳”。
type RowsColumnTypeDatabaseTypeName interface {
	Rows
	ColumnTypeDatabaseTypeName(index int) string
}

// RowsColumnTypeLength可以通过行来实现。它应该返回长度
// 如果列是可变长度类型，则为列类型的。如果列为
// 非可变长度类型ok应返回false。
// 如果长度不受系统限制以外的限制，则应返回math.MaxInt64。
// 以下是各种类型的返回值示例：
// 文本（math.MaxInt64，true）
// 瓦尔查尔（10）（10，正确）
// nvarchar（10）（10，真实）
// 十进制（0，false）
// int（0，false）
// bytea（30）（30，正确）
type RowsColumnTypeLength interface {
	Rows
	ColumnTypeLength(index int) (length int64, ok bool)
}

// RowsColumnTypeNullable可以由行实现。可为空的值应为空
// 如果已知该列可能为null，则为true；如果已知该列，则为false
// 不可为空。
// 如果列的可空性未知，则“确定”应为false。
type RowsColumnTypeNullable interface {
	Rows
	ColumnTypeNullable(index int) (nullable, ok bool)
}

// RowsColumnTypePrecisionScale可以通过行来实现。它应该会回来
// 小数类型的精度和小数位数。如果不适用，ok应为false。
// 以下是各种类型的返回值示例：
// 十进制（38，4）（38，4，真）
// int（0，0，false）
// 十进制（math.MaxInt64，math.MaxInt64，true）
type RowsColumnTypePrecisionScale interface {
	Rows
	ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool)
}

// Tx是一项交易。
type Tx interface {
	Commit() error
	Rollback() error
}

// RowsAffected实现插入或更新操作的结果
// 它使许多行发生变异。
type RowsAffected int64

var _ Result = RowsAffected(0)

func (RowsAffected) LastInsertId() (int64, error) {
	return 0, errors.New("LastInsertId is not supported by this driver")
}

func (v RowsAffected) RowsAffected() (int64, error) {
	return int64(v), nil
}

// ResultNoRows是一个预定义的结果，当DDL发生时，驱动程序将返回该结果
// 命令（如创建表）成功。它同时返回一个错误
// LastInsertId和RowsAffected。
var ResultNoRows noRows

type noRows struct{}

var _ Result = noRows{}

func (noRows) LastInsertId() (int64, error) {
	return 0, errors.New("no LastInsertId available after DDL statement")
}

func (noRows) RowsAffected() (int64, error) {
	return 0, errors.New("no RowsAffected available after DDL statement")
}
